<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <!-- Include the CesiumJS JavaScript and CSS files -->
    <!--Cesium js文件引入 -->
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script>
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<style>
    body {
        margin: 0;
    }
</style>
<body>
<!-- 视图显示容器 -->
<div id="cesiumContainer" style="width: 100vw;height: 100vh"></div>
<script>
    // 注册密钥: https://cesium.com/ion/tokens.
    // 账号密钥
    Cesium.Ion.defaultAccessToken =
        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzMGM5NjQ3OC1iNzI5LTQ1OGUtOGU4NC1lNjA1OTQ0OWFmYWMiLCJpZCI6NDU4NzgsImlhdCI6MTY2Nzk2MTM2Mn0.whkwTff2Jku7dVOpt5V4zrTTW8m-BV1fJQDeBsbmZn8'

    // 初始化容器 （容器：`cesiumContainer` ）
    const viewer = new Cesium.Viewer('cesiumContainer', {
        terrainProvider: Cesium.createWorldTerrain({
            requestVertexNormals: true,
            requestWaterMask: true
        })
    });


    // 折线
    const positions = Cesium.Cartesian3.fromDegreesArray([
        -75,
        39,
        -125,
        39,
        -125,
        75,
    ])
    const material = new Cesium.Material({
        fabric: {
            uniforms: {
                normalMap: '',
                count: 10.0,
                speed: 2.0
            },
            source: `
                    uniform sampler2D normalMap;
                    uniform float count;
                    czm_material czm_getMaterial(czm_materialInput materialInput)
                    {

                        float time = czm_frameNumber / 60.0 * speed;
                        vec2 uv = materialInput.st * 2.0 - 1.0;  // [0, 1] => [-1, 1]
                        vec3 color = vec3(0.8, 0.3, 0.4);
                        vec3 pixel = color;
                        float alpha = 1.0;

                        float t = fract(uv.x * count - time);


                        vec4 normalColor = texture2D(normalMap, vec2(uv.y + 0.5, fract(2.0 * t )));
                        pixel = normalColor.rgb;
                        alpha = normalColor.a;
                        vec3 fragColor = pixel;
                        if(t <= 0.5){
                            alpha = 0.0;
                        }
                        czm_material material = czm_getDefaultMaterial(materialInput);
                        material.diffuse = fragColor;
                        material.alpha = alpha;

                        return material;
                    }


                `
        },
        translucent: function () {
            return true
        }
    })
    // 自定义材质
    const aper = new Cesium.MaterialAppearance({
        material: material,
        translucent: true
    })

    const line = new Cesium.GroundPolylinePrimitive({
        geometryInstances: new Cesium.GeometryInstance({
            geometry: new Cesium.GroundPolylineGeometry({
                positions: positions,
                width: 20
            })
        }),
        appearance: aper
    })

    viewer.scene.primitives.add(line)


    function calculateCount(pixel = 100, positions) {

        const scene = viewer.scene
        const geodesic = new Cesium.EllipsoidGeodesic()
        const width = scene.canvas.clientWidth
        const height = scene.canvas.clientHeight
        const left = scene.camera.getPickRay(
            new Cesium.Cartesian2((width / 2) | 0, height - 1)
        )
        const right = scene.camera.getPickRay(
            new Cesium.Cartesian2((1 + width / 2) | 0, height - 1)
        )
        const globe = scene.globe
        const leftPosition = globe.pick(left, scene)
        const rightPosition = globe.pick(right, scene)
        if (!Cesium.defined(leftPosition) || !Cesium.defined(rightPosition)) {
            return
        }
        const leftCartographic = globe.ellipsoid.cartesianToCartographic(
            leftPosition
        )
        const rightCartographic = globe.ellipsoid.cartesianToCartographic(
            rightPosition
        )
        geodesic.setEndPoints(leftCartographic, rightCartographic)
        //1 像素实际距离
        let pixelDistance = geodesic.surfaceDistance

        //1 像素实际距离
        let sumLength = getDisTance(positions)


        const sumXY = sumLength / pixelDistance
        const count = sumXY / pixel

        return count.toFixed(2)
    }

    function getDisTance(positions) {
        let distance = 0;
        const scene = viewer.scene
        const globe = scene.globe
        for (let i = 0; i < positions.length - 1; i++) {
            /**根据经纬度计算出距离**/
            const geodesic = new Cesium.EllipsoidGeodesic();

            const start = globe.ellipsoid.cartesianToCartographic(
                positions[i]
            )
            const end = globe.ellipsoid.cartesianToCartographic(
                positions[i + 1]
            )

            geodesic.setEndPoints(
                start
                , end)
            let s = geodesic.surfaceDistance;
            //返回两点之间的距离
            s = Math.sqrt(
                Math.pow(s, 2) +
                Math.pow(start.height - end.height, 2)
            )
            distance = distance + s;
        }

        return distance.toFixed(3);
    }

    viewer.scene.postRender.addEventListener(() => {
        // pixel 一般是 线宽的 5 倍  可自己调整合适的效果

        const pixel = 20 * 5
        const count = calculateCount(pixel, positions)
        if (count) line.appearance.material.uniforms.count = count


    })


    const material2 = new Cesium.Material({
        fabric: {
            uniforms: {
                normalMap: '',
                count: 15.0,
                speed: 2.0,
                color: Cesium.Color.WHITE
            },
            source: `
                    uniform sampler2D normalMap;
                    uniform float count;
                    uniform vec4 color;

                    czm_material czm_getMaterial(czm_materialInput materialInput)
                    {

                        float time = czm_frameNumber / 60.0 * speed;
                        vec2 uv = materialInput.st * 2.0 - 1.0;  // [0, 1] => [-1, 1]
                        vec3 pixel =vec3(1.0);
                        float alpha = 1.0;

                        float t = fract(uv.x * count - time);


                        vec4 normalColor = texture2D(normalMap, vec2(fract(2.0 * t ),uv.y + 0.5));
                        pixel = normalColor.rgb;
                       vec3 fragColor =  color.rgb;
                        if(t <= 0.5){
                          if( pixel.r >0.0 && pixel.g > 0.0 && pixel.b >0.0){
                          fragColor =  pixel.rgb * color.rgb;
                            }
                        }




                        czm_material material = czm_getDefaultMaterial(materialInput);
                        material.diffuse = fragColor;
                        material.alpha = alpha;

                        return material;
                    }


                `
        },
        translucent: function () {
            return true
        }
    })
    // 自定义材质
    const aper2 = new Cesium.MaterialAppearance({
        material: material2,
        translucent: true
    })

    const volume = new Cesium.PolylineVolumeGeometry({
        vertexFormat: Cesium.VertexFormat.POSITION_NORMAL_AND_ST ,
        polylinePositions: Cesium.Cartesian3.fromDegreesArrayHeights([
            -75, 39, 200,
            -70.0, 39, 200
        ]),
        shapePositions: [
            new Cesium.Cartesian2(-5000, -5000),
            new Cesium.Cartesian2(5000, -5000),
            new Cesium.Cartesian2(5000, 5000),
            new Cesium.Cartesian2(-5000, 5000),
        ],
        cornerType: Cesium.CornerType.BEVELED,
    });

    const pro = new Cesium.Primitive({
        geometryInstances: new Cesium.GeometryInstance({
            geometry: volume
        }),
        appearance: aper2
    })

    viewer.scene.primitives.add(pro)
</script>
</div>
</body>
</html>
